//ITMD536 Software Testing and Maintenance.
//Final project <group assignment>
//Author: Wanglei ID:A20479012
//Face recognition system main program.
#include<iostream>
#include <cstring>
#include "Face.hpp"
#include <string.h>
#include <stdlib.h>
#include "Dboperator.hpp"
#include "Facecommon.hpp"

using namespace std;
static const float _score = 0.7;
static char buffer[128];
static char *current_time(void){
    //time_t now;
    //struct tm *timenow;
    //time(&now);
    //timenow = localtime(&now);
    //return strftime(timenow);

    time_t mytime;
    struct tm* timeinfo;
    time(&mytime);
    timeinfo = localtime(&mytime);
    strftime(buffer,sizeof(buffer),"%Y/%m/%d %H:%M:%S",timeinfo);
    //cout << "--->time: " << buffer << endl;
    return buffer;
}

int faceRegister(char *fname, char *uname){
    int ret;
    int det_facenum;
    Face face;
    vector<Bbox> finalBbox;
    FaceRecType recbox; //storge the detect result.
    cv::Mat mframe = cv::imread(fname, 1);
    if (mframe.empty()){
        fprintf(stderr, "cv::imread %s read failed.\n", fname);
        return faceError;
    }

    //detect the face in frame.
    ret = face.faceDetect(mframe, finalBbox);
    if(faceNormal != ret){
        det_facenum = 0;
        cout << "no face detected!" << endl;
        return faceNormal; 
    }

    //update the face number.
	det_facenum = finalBbox.size();
    if(1 != det_facenum){
        cout << "please make sure there is only one face in the picture." << endl;
        return faceNormal;
    }

    //for debug.
    //cv::Rect_<float> rect;
    //rect.x = finalBbox[0].x1;
    //rect.y = finalBbox[0].y1;
    //rect.width = finalBbox[0].x2 - finalBbox[0].x1;
    //rect.height = finalBbox[0].y2 - finalBbox[0].y1;
    //cv::rectangle(mframe, rect, cv::Scalar(255, 0, 0));
    //cv::imshow("detect face", mframe);
    //cv::waitKey(0);

    //face coordinate result for recognition(face feature calclation) box.
	recbox.box.x0 = finalBbox[0].x1; recbox.box.x1 = finalBbox[0].x2;
	recbox.box.y0 = finalBbox[0].y1; recbox.box.y1 = finalBbox[0].y2;
    //for recognition box.
    for (int i=0; i<5; ++i){
        recbox.box.landmark.x[i] = finalBbox[0].landmark.x[i];
	    recbox.box.landmark.y[i] = finalBbox[0].landmark.y[i];
    }
	
    //calculate the face feature values.
    face.faceRecognize(mframe, &recbox);
    //for debug:print the face feature values.
    //cout << "Face Feature Value:---------------------------------------------------------->" << endl;
	//for(int i=0; i<FACED_FEATURE_LEN; ++i)	
	//	printf("%f ", recbox.features[i]);
	//cout << endl << endl;

    //create or open a database.
    Dboperator dboperator;
    //write the feature data to database in face features table.
    //cout << "local time: " << current_time() << endl;
    //read the database, confirm whether the user is registered.
    dboperator.dbSelect(uname);
    if(0 == strcmp(uname, selectUserName)){
        //cout << "user name: " << uname << ", state: already registered." << endl;
        return faceNormal;
    }

    //register the user.
    current_time();
    dboperator.dbInsert(uname,buffer,recbox.features);
    return faceNormal;
}

int faceRecognition(char *fname){
    int ret;
    int det_facenum, rsize;
    float score;
    Face face;
    vector<Bbox> finalBbox;
    FaceRecType recbox; //storge the detect result.
    cv::Rect_<float> rect;
    
    cv::Mat mframe = cv::imread(fname, 1);
    if (mframe.empty()){
        fprintf(stderr, "cv::imread %s read failed.\n", fname);
        return faceError;
    }

    //detect the face in frame.
    ret = face.faceDetect(mframe, finalBbox);
    if(faceNormal != ret){
        det_facenum = 0;
        //cout << "no face detected!" << endl;
        return faceNormal; 
    }

    //update the face number.
	det_facenum = finalBbox.size();
    if(1 != det_facenum){
        //cout << "please make sure there is only one face in the picture." << endl;
        return faceNormal;
    }

    //face coordinate result for recognition(face feature calclation) box.
	recbox.box.x0 = finalBbox[0].x1; recbox.box.x1 = finalBbox[0].x2;
	recbox.box.y0 = finalBbox[0].y1; recbox.box.y1 = finalBbox[0].y2;
    //for recognition box.
    for (int i=0; i<5; ++i){
        recbox.box.landmark.x[i] = finalBbox[0].landmark.x[i];
	    recbox.box.landmark.y[i] = finalBbox[0].landmark.y[i];
    }
	
    //calculate the face feature values.
    face.faceRecognize(mframe, &recbox);
    //create or open a database.
    Dboperator dboperator;
    dboperator.dbFaceDataGet();
    //for debug, print face data.
    //for(unsigned int i=0; i<fData.size(); ++i){
    //    cout << "read user name: " << fData[i].username << endl;
    //    cout << "read user retister time: " << fData[i].regdate << endl;
    //    for(int sI=0; sI<FACED_FEATURE_LEN; ++sI)	
    //        cout << fData[i].features[sI] << " ";
	//    cout << endl;
    // }

    //compare the face feature value.
    rsize = fData.size();
    for(int i=0; i<rsize; ++i){
        face.faceCompare(fData[i].features, recbox.features, &score);
        if(_score <= score){
            cout << "matched! " << "name: " << fData[i].username << " - register date: " 
                << fData[i].regdate << " score: " << score << endl;
            //write the face information, and draw the face feature on the photo.
            rect.x = finalBbox[0].x1;
            rect.y = finalBbox[0].y1;
            rect.width = finalBbox[0].x2 - finalBbox[0].x1;
            rect.height = finalBbox[0].y2 - finalBbox[0].y1;
            cv::rectangle(mframe, rect, cv::Scalar(0,0,255,200));
            cv::putText(mframe,fData[i].username,cv::Point(10,50),CV_FONT_HERSHEY_PLAIN,3.0,cv::Scalar(0,0,255,200),3,8);
            cv::putText(mframe,fData[i].regdate,cv::Point(10,100),CV_FONT_HERSHEY_PLAIN,3.0,cv::Scalar(0,0,255,200),3,8);
            //cv::imshow(fData[i].username, mframe);
            //cv::waitKey(0);
            cv::imwrite("./images/result.jpg", mframe);
            return faceNormal;
        }
    }

    cout << "face recognition result: not matched." << endl;
    return faceNormal;
}

int faceRegShow(void){
    //create or open a database.
    Dboperator dboperator;
    dboperator.dbFaceDataShow();
    return faceNormal;
}

int faceRegClear(char *uname){
    Dboperator dboperator;
    if(nullptr != uname)
        dboperator.dbSelect(uname);
    if(nullptr == uname)
        dboperator.dbFaceDataClear(uname);
    else if(0 == strcmp(uname, selectUserName))
        dboperator.dbFaceDataClear(uname);
    else
        cout << "user name: " << uname << " not register in database." << endl;
    return faceNormal;
}